home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 June: Reference Library / Dev.CD Jun 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 26 / develop issue 26 code / truffles - display mgr. / superfly source / gdevicewindow.cp < prev    next >
Encoding:
Text File  |  1996-06-05  |  14.2 KB  |  564 lines

  1. /*
  2.     File:        GDeviceWindow.cp
  3.  
  4.     Contains:    A window that displays information about a GDevice
  5.                 
  6.     Written by: Kent Miller
  7.     
  8.     Copyright:    © 1995 Apple Computer
  9.  
  10.     Change History (most recent first):
  11.  
  12.  */
  13.  
  14. #include <Displays.h>
  15.  
  16. //Isn't it nice to double the size of your app so you
  17. //can do sprintf?
  18. #include <stdio.h>
  19. #include <string.h>
  20.  
  21. //Sprocket includes
  22. #include "MenuBar.h"
  23.  
  24. //SuperFly includes
  25. #include "GDeviceWindow.h"
  26. #include "GDeviceUtilities.h"
  27. #include "SuperFly.h"
  28.  
  29.  
  30. const short        kGDeviceWindowTemplateID = 1026;
  31.  
  32.  
  33. TGDeviceWindow::TGDeviceWindow()
  34.     {
  35.     this->theID = kInvalidDisplayID;
  36.     }
  37.  
  38. TGDeviceWindow::~TGDeviceWindow()
  39.     {
  40.     }    
  41.  
  42. WindowPtr
  43. TGDeviceWindow::MakeNewWindow(WindowPtr behindWindow)
  44.     {
  45.     WindowPtr        aWindow = GetNewWindow(kGDeviceWindowTemplateID,nil,behindWindow);
  46.     char            titleString[256];
  47.     GDHandle        thisWindowsGD, mirroredGD;
  48.     Rect            gdRect, windowRect;
  49.     DisplayIDType    mirroredID;
  50.     SInt16            hMove, vMove;
  51.     OSErr            err = noErr;
  52.     
  53.     if (aWindow)
  54.         {
  55.     //make the window exciting & different, center this window on it's GDevice
  56.         DMGetGDeviceByDisplayID(this->theID, &thisWindowsGD, false);
  57.         
  58.         // if this fails, we're in big trouble
  59.         if (thisWindowsGD == nil)
  60.             {
  61.             CloseWindow(aWindow);
  62.             return nil;
  63.             }
  64.         
  65.         gdRect = (**thisWindowsGD).gdRect;
  66.         OffsetRect(&gdRect, -gdRect.left, -gdRect.top);  //move it to 0,0
  67.         
  68.         windowRect = aWindow->portRect;
  69.         OffsetRect (&windowRect, -windowRect.left, -windowRect.top);
  70.         
  71.         CenterRectInRect(&gdRect, &windowRect, &hMove, &vMove);
  72.         
  73.         hMove = (**thisWindowsGD).gdRect.left + hMove;
  74.         vMove = (**thisWindowsGD).gdRect.top + vMove;
  75.         
  76.         MoveWindow(aWindow, hMove, vMove, false);        
  77.  
  78.         //Create the title for the window out of Display's ID
  79.         sprintf(titleString, "Display ID = %ld", this->theID);
  80.         
  81.         //Add the display IDs of all mirrored displays to the window title.
  82.         //Hopefully, the title won't grow too much.
  83.         
  84.         mirroredGD = thisWindowsGD;
  85.         while (err == noErr)
  86.             {
  87.             err = DMGetNextMirroredDevice(mirroredGD, &mirroredGD);
  88.             if (mirroredGD == thisWindowsGD) 
  89.                 break;  //we've come around in a loop
  90.             if (err == noErr)
  91.                 {
  92.                 err = DMGetDisplayIDByGDevice(mirroredGD, &mirroredID, false);
  93.                 if ((strlen(titleString)< 230))  //Watch out for big window titles!
  94.                     sprintf(titleString, "%s, %ld", titleString, mirroredID);
  95.                 }
  96.             
  97.             }
  98.  
  99.         c2pstr(titleString);
  100.  
  101.         SetWTitle(aWindow,(unsigned char *)titleString);
  102.         ShowWindow(aWindow);
  103.         }
  104.  
  105.     return aWindow;
  106.     }
  107.  
  108. void
  109. TGDeviceWindow::Click(EventRecord * /* anEvent */)
  110.     {
  111.     this->Select();
  112.     }
  113.  
  114. void
  115. TGDeviceWindow::Activate(Boolean activating)
  116.     {
  117.     if (activating)
  118.         this->Select();
  119.     }
  120.  
  121. OSErr            
  122. TGDeviceWindow::SetUpData(GDHandle theGD)
  123.     {
  124.     OSErr     err;
  125.     
  126.     err = DMGetDisplayIDByGDevice(theGD, &this->theID, false);
  127.  
  128.     this->CreateWindow();
  129.  
  130.     return (err);
  131.     }
  132.     
  133. void
  134. TGDeviceWindow::Draw(void)
  135.     {
  136.     unsigned char                 s[256];
  137.     DeviceLoopDrawingUPP        myDrawingProcUPP;
  138.     GrafPtr                        savePort;
  139.     RgnHandle                    myWindowsRgn;
  140.     SInt16                        familyID;
  141.     Point                        p = { 20, 20};  //Draw Text Here
  142.     GDHandle                    theGD;
  143.     
  144.     GetPort(&savePort);
  145.     SetPort(this->fWindow);
  146.     
  147.     GetFNum("\pHelvetica",&familyID);
  148.     TextFont(familyID);
  149.     TextSize(18);
  150.     ForeColor(blackColor);
  151.     
  152.     ClipRect(&(this->fWindow->portRect));
  153.         
  154.     //Make a region that is my Window's StrucRgn only in local coordinates.
  155.     myWindowsRgn = NewRgn();
  156.     if (!myWindowsRgn)
  157.         return;
  158.     CopyRgn(( (WindowPeek)this->fWindow)->strucRgn, myWindowsRgn);
  159.     OffsetRgn(myWindowsRgn, -(**myWindowsRgn).rgnBBox.left, -(**myWindowsRgn).rgnBBox.top);; 
  160.  
  161.  
  162.     //For this app, we will draw the parts of the window that are common to them 
  163.     //using quickdraw commands and the parts that are different using device loop.
  164.     //
  165.     //First, use Device Loop to draw.  When there is a mirrored device, the
  166.     //drawing proc will be called twice and we can draw different things each time.
  167.     //We could draw the same thing each time, but that would be boring.
  168.     myDrawingProcUPP = NewDeviceLoopDrawingProc (GDeviceWindowDrawingProc);
  169.     DeviceLoop( myWindowsRgn, myDrawingProcUPP, (SInt32) this->fWindow, 0);
  170.     DisposeRoutineDescriptor(myDrawingProcUPP);
  171.     DisposeRgn(myWindowsRgn);
  172.     
  173.     //Then draw the common parts.  We are doing things in this order since the device
  174.     //loop proc fills the window's background.
  175.     DMGetGDeviceByDisplayID( this->theID, &theGD, false );
  176.     
  177.     sprintf    ((char *)s, "Global rect: (%d,%d) (%d,%d)", 
  178.             (**theGD).gdRect.top, (**theGD).gdRect.left,
  179.             (**theGD).gdRect.bottom, (**theGD).gdRect.right);
  180.     
  181.     c2pstr((char *)s);
  182.     MoveTo(p.h,p.v);
  183.     DrawString(s);
  184.  
  185.  
  186.     SetPort(savePort);
  187.     }
  188.  
  189. void DrawThisCStringHere(unsigned char * s, SInt16 h, SInt16 v)
  190. //Converts the string to a PString in place
  191.     {
  192.     MoveTo(h, v);
  193.     c2pstr((char *)s);
  194.     DrawString(s);
  195.     }
  196.  
  197. void SetRampRGBColor(RGBColor * theRGB, SInt16 value, SInt16 rampColor)
  198.     {
  199.         theRGB->red        = 0;
  200.         theRGB->green    = 0;
  201.         theRGB->blue    = 0;
  202.         
  203.         switch (rampColor)
  204.             {
  205.             case 0:    
  206.                 theRGB->red        = value;
  207.                 break;
  208.                 
  209.             case 1:    
  210.                 theRGB->green    = value;
  211.                 break;
  212.                 
  213.             case 2:    
  214.                 theRGB->blue    = value;
  215.                 break;
  216.             
  217.             case 3: //a Gray ramp
  218.                 theRGB->red        = value;
  219.                 theRGB->green    = value;
  220.                 theRGB->blue     = value;
  221.                 break;
  222.             }
  223.     }
  224.  
  225.  
  226. void DrawARamp(SInt16 depth, Rect * rampRect )
  227. //Don't ask me to comment this code, I just ripped it off from a "reliable" source.
  228. //For indexed color modes, use the system color table.
  229. //For direct color modes, just draw ramps.
  230.     {
  231.     SInt16            i, j, h, v;
  232.     RGBColor        rgb, savedFore;
  233.     Rect            tempRect;
  234.     SInt32            hsteps;
  235.     SInt16            vsteps,hsides,vsides;    
  236.     
  237.     GetForeColor(&savedFore);
  238.  
  239.     if (depth > 8) //direct ramp
  240.         {
  241.         hsteps = rampRect->right - rampRect->left;
  242.         hsides = 1;
  243.         vsides = (rampRect->bottom - rampRect->top) / 4;
  244.         for (i = 0; i< hsteps; i++)
  245.             {
  246.             j = ((i+1) * (0x0000FFFF / hsteps)) - 1;
  247.             MoveTo(rampRect->left + i, rampRect->top);
  248.             SetRampRGBColor(&rgb, j, 0);
  249.             RGBForeColor(&rgb);
  250.             Line(0, vsides);
  251.             SetRampRGBColor(&rgb, j, 1);
  252.             RGBForeColor(&rgb);
  253.             Line(0, vsides);
  254.             SetRampRGBColor(&rgb, j, 2);
  255.             RGBForeColor(&rgb);
  256.             Line(0, vsides);
  257.             SetRampRGBColor(&rgb, j, 3);
  258.             RGBForeColor(&rgb);
  259.             Line(0, vsides-1);
  260.             }
  261.         }
  262.     else //Indexed ramp - this doesn't behave like "Monitors" does in Grayscale mode.
  263.          //If you want Grayscale ramps to behave differently, you could attach a palette
  264.          //to the window and call PMForeColor.
  265.         {
  266.         //window
  267.         Handle            clutRsrc;
  268.         PaletteHandle    ourPalette;
  269.         
  270.         clutRsrc = RGetResource('clut', depth);
  271.         ourPalette = NewPalette(256, CTabHandle(clutRsrc), pmExplicit, 0);
  272.         ReleaseResource(clutRsrc);
  273.  
  274.         hsteps = Max( 1 << (depth/2+1) , 2);
  275.         vsteps = Max( 1 << (depth/2-1) , 1);
  276.         hsides = (rampRect->right - rampRect->left) / hsteps;
  277.         vsides = (rampRect->bottom - rampRect->top) / vsteps;
  278.  
  279.  
  280.         for (i=0; i < vsteps; i++)
  281.             for (j=0; j < hsteps; j++)
  282.             {
  283.                 GetEntryColor(ourPalette, ((1<< depth) - 1) - (i*hsteps+j), &rgb);
  284.                 RGBForeColor(&rgb);
  285.                 
  286.                 h = j * hsides;
  287.                 v = i * vsides;
  288.                 SetRect(&tempRect, rampRect->left + h, rampRect->top + v, 
  289.                                 rampRect->left + h + hsides,  rampRect->top + v + vsides);
  290.                 FillRect(&tempRect, &qd.black);
  291.             }
  292.         DisposePalette(ourPalette);
  293.                 
  294.         }
  295.     
  296.     RGBForeColor(&savedFore);
  297.     }
  298.  
  299. void DrawMiniMonitors(Rect *drawHere, GDHandle thisGDevice)
  300.     {
  301.     RgnHandle        theGrayRgn = LMGetGrayRgn();
  302.     TLinkedList        *myGDList;
  303.     GDHandle        theGD;
  304.     Rect            r, drawHereTemp;
  305.     RgnHandle        saveClip = NewRgn();
  306.     Point            origin;
  307.     SInt16             hOffset, vOffset;
  308.     PixPatHandle    theDesktopPattern;
  309.     
  310.     //For speed, we should probably cache this list since Display Manager notification
  311.     //tells us every time this changes.
  312.     myGDList = BuildAListOfUniqueDevices();
  313.     
  314.     //start framing the devices 
  315.     EraseRect(drawHere);
  316.     FrameRect(drawHere);
  317.     
  318.     GetClip(saveClip);
  319.     ClipRect(drawHere);
  320.     
  321.     //Figure out where the 0,0 point will be in the drawHere rect.
  322.     //Set r to the desktop rgn and scale it
  323.     r = (**theGrayRgn).rgnBBox;
  324.     r.top /= 10;
  325.     r.left /= 10;
  326.     r.bottom/= 10;
  327.     r.right /= 10;    
  328.  
  329.     //Where is 0,0 in the scaled rectangle?
  330.     origin.h = ( - r.left );      //r.left will either be zero or some negative number
  331.     origin.v = ( - r.top );        //ditto for the top
  332.  
  333.     OffsetRect( &r, -r.left, -r.top );
  334.     
  335.     //Center it in theDrawHere rect
  336.     //This might not work if r's bounds are bigger than the drawHere bounds, who knows?
  337.     drawHereTemp = *drawHere;
  338.     OffsetRect( &drawHereTemp, -drawHereTemp.left, -drawHereTemp.top );
  339.     CenterRectInRect(&drawHereTemp, &r, &hOffset, &vOffset);
  340.     OffsetRect( &r, hOffset, vOffset);
  341.     
  342.     //Now, just find where the origin is in the scaled rectangle
  343.     origin.h += r.left + drawHere->left;
  344.     origin.v += r.top + drawHere->top;
  345.     
  346.         
  347.     theGD = (GDHandle) myGDList->GetFirstListElem();
  348.     while (theGD)
  349.         {
  350.         r = (**theGD).gdRect;
  351.         
  352.         r.top /= 10;
  353.         r.left /= 10;
  354.         r.bottom/= 10;
  355.         r.right /= 10;
  356.         
  357.         OffsetRect(&r, origin.h, origin.v); 
  358.         
  359.         FrameRect(&r);
  360.         
  361.         //If this is my rect, then fill it with the desktop rect
  362.         //If it isn't, fill it with Gray
  363.         InsetRect(&r, 1, 1);
  364.         if ( EqualRect (&(**theGD).gdRect, &(**thisGDevice).gdRect))
  365.             {
  366.             //Get the current desktop pattern from the system file.
  367.             theDesktopPattern = GetPixPat(16);
  368.             if (theDesktopPattern)
  369.                 {
  370.                 FillCRect(&r, theDesktopPattern);
  371.                 DisposePixPat(theDesktopPattern);
  372.                 }
  373.             }
  374.         else
  375.             FillRect(&r, &qd.gray);
  376.  
  377.         //If this is the main display, draw a wonky little menu bar
  378.         if (TestDeviceAttribute (theGD, mainScreen))
  379.             {
  380.             r.bottom = r.top + 5;
  381.             EraseRect(&r);
  382.             MoveTo( r.left +3, r.top+2);
  383.             Line(3, 0);
  384.             Move(2, 0);
  385.             Line(1, 0);
  386.             Move(3, 0);
  387.             Line(4, 0);
  388.             Move(2, 0);
  389.             Line(2, 0);
  390.             }
  391.  
  392.         theGD = (GDHandle) myGDList->GetNextListElem(theGD);
  393.         }
  394.     
  395.     SetClip(saveClip);
  396.     DisposeRgn(saveClip);
  397.     delete myGDList;
  398.     }
  399.  
  400. pascal void GDeviceWindowDrawingProc (    SInt16        depth,
  401.                                         SInt16        deviceFlags,
  402.                                         GDHandle    targetDevice,
  403.                                         SInt32        userData)
  404.     {
  405. #pragma unused(deviceFlags)
  406.     Rect            rampRect, monitorsRect;
  407.     RGBColor        myGray = {0xEEEE,0xEEEE,0xEEEE};
  408.     SInt16            windowWidth;
  409.     
  410.     if (depth > 4) //Fill the window with gray to get that look that's all the rage these days
  411.         {
  412.         RGBForeColor(&myGray);
  413.         PaintRect( &((WindowPtr) userData)->portRect);
  414.         }
  415.  
  416.     ForeColor(blackColor);
  417.  
  418.     //Now make the rampRect
  419.     rampRect = ((WindowPtr) userData)->portRect;
  420.     rampRect.bottom -= 5; //A little bit from the bottom
  421.     rampRect.top = rampRect.bottom - 48;  //Ramp height needs to be divisible by 8
  422.  
  423.     //Get a little from the edges distance first
  424.     rampRect.left += 16;
  425.     rampRect.right -= 16;
  426.     //Ramp width needs to be be divisible by 32 so the 8-bit palette will
  427.     //draw correctly.
  428.     windowWidth = rampRect.right - rampRect.left;    
  429.     rampRect.left += (windowWidth % 32) / 2;
  430.     rampRect.right -= (windowWidth % 32) / 2;
  431.         
  432.     DrawARamp(depth, &rampRect );
  433.     PenSize(2,2);
  434.     FrameRect(&rampRect);
  435.     PenSize(1,1);
  436.  
  437.     //Now make a rect for the mini-monitors display
  438.     monitorsRect = ((WindowPtr) userData)->portRect;
  439.     monitorsRect.top += 50;
  440.     monitorsRect.bottom -= 80;
  441.     //Make the right and left match the ramp for looks
  442.     monitorsRect.left = rampRect.left;
  443.     monitorsRect.right = rampRect.right ;
  444.     //Draw that sucker.
  445.     DrawMiniMonitors(&monitorsRect, targetDevice);
  446.  
  447.  
  448.     }
  449.     
  450.  
  451. void
  452. TGDeviceWindow::Drag(Point startPoint)
  453.     {
  454. //**Bad UI Alert**
  455. //We are overriding this method because we don't want to allow the
  456. //user to drag a window of the device it's on.
  457.     GrafPtr        savePort;
  458.     RgnHandle    draggingRegion;
  459.     long        dragResult;
  460.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  461.     GDHandle     thisGD;
  462.     Rect        limitRect, slopRect;
  463.     Rect        *windowGlobalRect;
  464.     OSErr        err;
  465.     
  466.     if (WaitMouseUp())        //    de-bounce?
  467.         {
  468.         // Set up the Window Manager port.
  469.     
  470.         GetPort(&savePort);
  471.         SetPort(gWindowManagerPort);
  472.         SetClip(GetGrayRgn());
  473.  
  474.          err = DMGetGDeviceByDisplayID(this->theID, &thisGD, false);
  475.  
  476.         if (err == noErr)
  477.             {
  478.             //Don't want let user drag off this device, so we will set up the slop and limit
  479.             //rectangles to stop them from dragging off the window
  480.             slopRect = (**thisGD).gdRect;
  481.             GlobalToLocal( (Point *) & limitRect.top);
  482.             GlobalToLocal( (Point *) & limitRect.bottom);
  483.             if (MenuBarOnThisScreen(thisGD))
  484.                 slopRect.top += LMGetMBarHeight();
  485.                 
  486.             
  487. //            if (TestDeviceAttribute (thisGD, mainScreen)) //Account for the menu bar
  488. //                slopRect.top += LMGetMBarHeight();
  489.  
  490.  
  491.             //Set the limit rect to be the bounds of the GDevice adjusted by the offset of the 
  492.             //start point in the window. 
  493.             limitRect = slopRect;
  494.             windowGlobalRect = &( (**(windowAsWindowPeek)->strucRgn).rgnBBox);
  495.             limitRect.top         = limitRect.top + (startPoint.v - windowGlobalRect->top );
  496.             limitRect.left         = limitRect.left + (startPoint.h - windowGlobalRect->left );
  497.             limitRect.bottom     = limitRect.bottom - (windowGlobalRect->bottom - startPoint.v);
  498.             limitRect.right     = limitRect.right - (windowGlobalRect->right - startPoint.h);
  499.  
  500.             draggingRegion = NewRgn();
  501.             CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
  502.             dragResult = DragGrayRgn(draggingRegion, startPoint, &limitRect, &slopRect, noConstraint, nil);
  503.             DisposeRgn(draggingRegion);
  504.             }
  505.     
  506.         SetPort(savePort);    //    Get back to old port
  507.  
  508.         if ((dragResult != 0) && (dragResult != 0x80008000))
  509.             {
  510.             this->Nudge((dragResult & 0xFFFF),(dragResult >> 16));
  511.             }
  512.         }
  513.  
  514.     }
  515.  
  516. void
  517. TGDeviceWindow::WindowOnDevice() // •••• PUT THIS IN UTILITIES?
  518.     {
  519.     GDHandle            theGD;
  520.     Rect                gdRect, intersectionRect, windowRect;
  521.     WindowPeek            windowAsWindowPeek = (WindowPeek) this->fWindow;
  522.     SInt16                hMove, vMove;
  523.  
  524.     DMGetGDeviceByDisplayID(this->theID, &theGD, false);
  525.     if (theGD)
  526.         {
  527.         SectRect( &(**theGD).gdRect, &(**windowAsWindowPeek->strucRgn).rgnBBox, &intersectionRect);
  528.         if (! EqualRect(&intersectionRect,&(**windowAsWindowPeek->strucRgn).rgnBBox))
  529.              {
  530.                 gdRect = (**theGD).gdRect;
  531.                 windowRect = (**windowAsWindowPeek->strucRgn).rgnBBox;
  532.                 CenterRectInRect(&gdRect, &windowRect, &hMove, &vMove);
  533.                 
  534.                 hMove = (**windowAsWindowPeek->contRgn).rgnBBox.left + hMove;
  535.                 vMove = (**windowAsWindowPeek->contRgn).rgnBBox.top + vMove;
  536.  
  537.                 MoveWindow(this->fWindow, hMove, vMove, false);        
  538.  
  539.              }
  540.         
  541.         }
  542.     }
  543.     
  544. void
  545. TGDeviceWindow::AdjustMenusBeforeMenuSelection(void)
  546.     {
  547.     Boolean    mirrorOn = false;
  548.     Boolean    canMirror = false;
  549.  
  550.     DMCanMirrorNow(&canMirror);
  551.     
  552.     if (!canMirror) //can't mirror, so disable the menu and bail
  553.         gMenuBar->EnableAndCheckCommand(cMirroring, false, false);
  554.     else 
  555.         {
  556.         DMIsMirroringOn(&mirrorOn);
  557.         if (mirrorOn)
  558.             gMenuBar->EnableAndCheckCommand(cMirroring, true, true);
  559.         else
  560.             gMenuBar->EnableAndCheckCommand(cMirroring, true, false);
  561.         }
  562.     }
  563.  
  564.